package cn.ondraw.ragflow.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.http.*;
import org.springframework.http.client.MultipartBodyBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;

@Service
@Slf4j
@RequiredArgsConstructor
public class PythonApiCaller {

    private static final HttpClient HTTP_CLIENT = HttpClients.createDefault();
    private static final String PYTHON_API_URL = "http://1.95.79.99:8038";
    private static final String TOKEN = "Bearer ragflow-k2NTg4NDE2MWNjYzExZjA5N2ExZjI2ZD";

    private final TokenManager tokenManager;

    private ResponseEntity<?> handleException(String action, Exception e) {
        log.error("{} 请求异常: {}", action, e.getMessage(), e);
        throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage());
    }

    public ResponseEntity<?> callGetApi(String url) {
        return callGetApi(url, true);
    }

    public ResponseEntity<byte[]> callGetApiForFile(String url) {
        return callGetApiForFile(url, true);
    }

    public ResponseEntity<?> callPostApi(String interfaceUrl, Object request) {
        return callPostApi(interfaceUrl, request, true);
    }

    public ResponseEntity<String> callPostApiWithFiles(String url, MultipartFile[] files) {
        return callPostApiWithFiles(url, files, true);
    }

    public ResponseEntity<?> callPutApi(String interfaceUrl, Object request) {
        return callPutApi(interfaceUrl, request, true);
    }

    public ResponseEntity<?> callDeleteApi(String url, Object requestBody) {
        return callDeleteApi(url, requestBody, true);
    }

    public ResponseEntity<?> callGetApi(String url, boolean defaultToken) {
        String token = defaultToken ? TOKEN : tokenManager.getToken();
        try {
            String requestUrl = PYTHON_API_URL + url;
            log.info("请求url:{} 请求参数:{}", requestUrl, "GET请求无参数");
            HttpGet httpGet = new HttpGet(requestUrl);
            httpGet.setHeader("Authorization", token);
            HttpResponse response = HTTP_CLIENT.execute(httpGet);
            String result = EntityUtils.toString(response.getEntity());
            checkResponseCode(result);
            return ResponseEntity.status(response.getStatusLine().getStatusCode()).body(result);
        } catch (IOException e) {
            return handleException("callGetApi", e);
        }
    }

    public ResponseEntity<byte[]> callGetApiForFile(String url, boolean defaultToken) {
        String token = defaultToken ? TOKEN : tokenManager.getToken();
        try {
            String requestUrl = PYTHON_API_URL + url;
            log.info("请求url:{} 请求参数:{}", requestUrl, "GET请求无参数");
            HttpGet httpGet = new HttpGet(requestUrl);
            httpGet.setHeader("Authorization", token);
            HttpResponse response = HTTP_CLIENT.execute(httpGet);
            byte[] result = EntityUtils.toByteArray(response.getEntity());
            return ResponseEntity.status(response.getStatusLine().getStatusCode()).body(result);
        } catch (IOException e) {
            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage());
        }
    }

    public ResponseEntity<?> callPostApi(String interfaceUrl, Object request, boolean defaultToken) {
        String token = defaultToken ? TOKEN : tokenManager.getToken();
        try {
            String requestUrl = PYTHON_API_URL + interfaceUrl;
            String requestJson = request != null ? JSONUtil.toJsonStr(request) : null;
            log.info("请求url:{} 请求参数:{}", requestUrl, requestJson != null ? requestJson : "无参数");
            HttpPost httpPost = new HttpPost(requestUrl);
            httpPost.setEntity(new StringEntity(requestJson != null ? requestJson : "{}", StandardCharsets.UTF_8));
            httpPost.setHeader("Content-type", "application/json");
            httpPost.setHeader("Authorization", token);
            HttpResponse response = HTTP_CLIENT.execute(httpPost);
            String result = EntityUtils.toString(response.getEntity());
            // 如果不是以 "data:" 开头才校验
            if (result == null || !result.trim().startsWith("data")) {
                checkResponseCode(result);
            }
            return ResponseEntity.status(response.getStatusLine().getStatusCode()).body(result);
        } catch (IOException e) {
            return handleException("callPostApi", e);
        }
    }

    public ResponseEntity<String> callPostApiWithFiles(String url, MultipartFile[] files, boolean defaultToken) {
        String token = defaultToken ? TOKEN : tokenManager.getToken();
        try {
            String requestUrl = PYTHON_API_URL + url;
            log.info("请求url:{} 请求参数:{}", requestUrl, "文件上传请求，文件数量: " + (files != null ? files.length : 0));
            MultipartBodyBuilder builder = new MultipartBodyBuilder();
            if (files != null) {
                for (MultipartFile file : files) {
                    builder.part("file", file.getResource());
                }
            }
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
            headers.set("Authorization", token);
            HttpEntity<?> requestEntity = new HttpEntity<>(builder.build(), headers);
            RestTemplate restTemplate = new RestTemplate();
            return restTemplate.postForEntity(PYTHON_API_URL + url, requestEntity, String.class);
        } catch (Exception e) {
            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage());
        }
    }

    public ResponseEntity<?> callPutApi(String interfaceUrl, Object request, boolean defaultToken) {
        String token = defaultToken ? TOKEN : tokenManager.getToken();
        try {
            String requestUrl = PYTHON_API_URL + interfaceUrl;
            String requestJson = request != null ? JSONUtil.toJsonStr(request) : null;
            log.info("请求url:{} 请求参数:{}", requestUrl, requestJson != null ? requestJson : "无参数");
            HttpPut httpPut = new HttpPut(requestUrl);
            httpPut.setEntity(new StringEntity(requestJson != null ? requestJson : "{}", StandardCharsets.UTF_8));
            httpPut.setHeader("Content-type", "application/json");
            httpPut.setHeader("Authorization", token);
            HttpResponse response = HTTP_CLIENT.execute(httpPut);
            String result = EntityUtils.toString(response.getEntity());
            checkResponseCode(result);
            return ResponseEntity.status(response.getStatusLine().getStatusCode()).body(result);
        } catch (IOException e) {
            return handleException("callPutApi", e);
        }
    }

    public ResponseEntity<?> callDeleteApi(String url, Object requestBody, boolean defaultToken) {
        String token = defaultToken ? TOKEN : tokenManager.getToken();
        try {
            String requestUrl = PYTHON_API_URL + url;
            String requestJson = requestBody != null ? JSONUtil.toJsonStr(requestBody) : null;
            log.info("请求url:{} 请求参数:{}", requestUrl, requestJson != null ? requestJson : "无参数");

            HttpDeleteWithBody httpDelete = new HttpDeleteWithBody(requestUrl);
            httpDelete.setEntity(new StringEntity(requestJson != null ? requestJson : "{}", StandardCharsets.UTF_8));
            httpDelete.addHeader("Content-type", "application/json");
            httpDelete.addHeader("Authorization", token);

            HttpResponse response = HTTP_CLIENT.execute(httpDelete);
            String result = EntityUtils.toString(response.getEntity());
            checkResponseCode(result);
            return ResponseEntity.status(response.getStatusLine().getStatusCode()).body(result);
        } catch (Exception e) {
            return handleException("callDeleteApiWithBody", e);
        }
    }

    private static class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase {
        public HttpDeleteWithBody(String url) {
            super();
            setURI(URI.create(url));
        }

        @Override
        public String getMethod() {
            return "DELETE";
        }
    }

    private void checkResponseCode(String result) {
        // 只处理标准 JSON 格式（以 { 开头），否则直接返回
        if (result == null || !result.trim().startsWith("{")) {
            return;
        }
        try {
            JSONObject jsonObject = JSONUtil.parseObj(result);
            int code = jsonObject.getInt("code", -1);
            if (code != 0) {
                log.debug("请求python失败: {}", result);
                throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "响应代码不为0，code: " + code);
            }
        } catch (Exception e) {
            log.error("checkResponseCode 错误: {}, 原因: {}", result, e.getMessage());
            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "解析响应数据失败: " + e.getMessage());
        }
    }

    /**
     * SSE 流式响应
     *
     * @param interfaceUrl 接口地址
     * @param request      请求参数
     * @return 结果
     * @throws IOException 异常
     */
    public HttpResponse callPostSSEApiRaw(String interfaceUrl, Object request) throws IOException {
        String requestUrl = PYTHON_API_URL + interfaceUrl;
        String requestJson = request != null ? JSONUtil.toJsonStr(request) : null;
        log.info("请求url:{} 请求参数:{}", requestUrl, requestJson != null ? requestJson : "无参数");
        HttpPost httpPost = new HttpPost(requestUrl);
        httpPost.setEntity(new StringEntity(requestJson != null ? requestJson : "{}", StandardCharsets.UTF_8));
        httpPost.setHeader("Content-type", "application/json");
        httpPost.setHeader("Authorization", tokenManager.getToken());
        return HTTP_CLIENT.execute(httpPost);
    }

}
